
public class linkedList {
	
	

	
	private node  head;
	private node  tail;
	private int size = 0;
	
	public linkedList(){
		this.head = null;
		this.tail = null;
	}
	
	public node  addToHead(Object data){
		node  tempNode = new node(data);
		
		
		if (this.head == null){
			this.head = tempNode;
			this.tail = tempNode;
		
		}else{
			tempNode.previous = this.head;
			this.head.next = tempNode;
			this.head = tempNode;
			
		}
		
		
		this.size++ ; 			// increase the size of the list.
	return tempNode;
	}
	
	public Object removeNode(node nodeToRemove){
		assert nodeToRemove != null : "You are trying to remove a null value form the list - it is illeagal.";   //in case we are trying to remove an item from an empty list.
		Object data = nodeToRemove.data;
		if (nodeToRemove.previous == null){					
			if (nodeToRemove.next == null){					//in case the node we want to remove is the only link in the list
				this.head = null;
				this.tail = null;
			}else{
				nodeToRemove.next.previous = null; 			//in case the node we want to remove is the last node in the list.
				this.tail = nodeToRemove.next;
			}
		}else if (nodeToRemove.next == null){				//in case the node we want to remove is the first node in the list.					
			this.head = nodeToRemove.previous;
			nodeToRemove.previous.next = null;
		}else{
			nodeToRemove.next.previous = nodeToRemove.previous;
			nodeToRemove.previous.next = nodeToRemove.next;
		}	
		//assert nodeToRemove.next == nodeToRemove: "crazy 1";
		this.size--;
		return data;
	}
	
	public Object removeTail(){							//removes an item from the end of the list.
		return removeNode(this.tail);
	}
	
	public node addToTail(Object data){
		return AddToListBeforeNode(tail, data);
		
	}
	
	public node AddToListBeforeNode (node  nodeToAddBefore , Object data){
		node  returnNode;
		if (nodeToAddBefore == null){		// if we want to add a nod at the head of the list.
			returnNode = this.addToHead(data);
		}else{
			 node  newNode = new node  (data);	
			 returnNode = newNode;
			 
			if (nodeToAddBefore.previous == null){			// if we want to add a nod at the tail of the list.
				newNode.next = nodeToAddBefore;
				nodeToAddBefore.previous = newNode;
				this.tail = newNode;
			}else{																// if we want to add to somewhere in the middle.
				newNode.next = nodeToAddBefore;
				newNode.previous = nodeToAddBefore.previous;
				nodeToAddBefore.previous.next = newNode;
				nodeToAddBefore.previous = newNode;
				
			}
			//assert newNode.next != newNode: "crazy 2";
			this.size++;
		}
		
		//assert nodeToAddBefore.next == nodeToAddBefore: "crazy 3";
		
		return returnNode;
	}
	
	public int size(){												// returns the size of the list
		return this.size;
	}
	
	public node peekTail(){											//returns the Tail of the list.
		return this.tail;
	}
	
	public node peekHead(){											//returns the head of the list.
		return this.head;
	}
	
	

}
